/*
 moxl - Modular XML Library
 Copyright (c) 2007, Malcolm Sparks

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package moxl.parser.markup.states;

import moxl.parser.ParserException;
import moxl.parser.assemblers.cdata.CharacterDataAssembler;
import moxl.parser.assemblers.cdatasect.CharacterDataSectionAssembler;
import moxl.parser.assemblers.closeelement.CloseElementAssembler;
import moxl.parser.assemblers.comment.CommentAssembler;
import moxl.parser.assemblers.openelement.OpenElementAssembler;
import moxl.parser.assemblers.pi.ProcessingInstructionAssembler;
import moxl.parser.markup.Markup;
import moxl.tokenizer.Token;
import moxl.tokenizer.TokenStream;
import moxl.tokenizer.TokenizerException;
import moxl.tokenizer.xml.XmlTokenType;

/**
 * A state representing production 43 in XML 1.0
 */
public class ElementContentStateDelegate implements XmlDocumentParserStateDelegate
{
	public Markup parseNextMarkupFromStream(TokenStream tstream, XmlParserContext ctx) throws ParserException, TokenizerException
	{
		int c = 0;
		try
		{
			c = tstream.peekNextCharacter();
		}
		catch (TokenizerException e)
		{
			throw new ParserException("Failed to peek ahead in element content", tstream.getPosition(), e);
		}

		if (c == '<')
		{
			// OK, it's safe to lookahead.
			Token nextToken = tstream.lookahead(1);

			switch ((XmlTokenType) nextToken.getType())
			{
			case OPEN_CHEVRON:
				return new OpenElementAssembler().assembleMarkupFromStream(tstream);

			case OPEN_CHEVRON_SLASH:
				return new CloseElementAssembler().assembleMarkupFromStream(tstream);

			case OPEN_COMMENT:
				return new CommentAssembler().assembleMarkupFromStream(tstream);

			case OPEN_CHEVRON_EXCLAMATION_MARK:
				if (lookaheadIsCharacterDataSection(tstream))
				{
					return new CharacterDataSectionAssembler().assembleMarkupFromStream(tstream);
				}
				else
				{
					throw new ParserException("Unexpected token in element content: " + nextToken, nextToken.getLocation());
				}

			case OPEN_CHEVRON_QUESTION_MARK:
				return new ProcessingInstructionAssembler().assembleMarkupFromStream(tstream);

			default:
				throw new ParserException("Unexpected token in element content: " + nextToken, nextToken.getLocation());
			}
		}
		else
		{
			return new CharacterDataAssembler().assembleMarkupFromStream(tstream);
		}
	}

	private boolean lookaheadIsCharacterDataSection(TokenStream tstream) throws ParserException, TokenizerException
	{
		if (tstream.lookahead(2).getType() != XmlTokenType.OPEN_BRACKET)
		{
			return false;
		}
		if (tstream.lookahead(3).getType() != XmlTokenType.NAME)
		{
			return false;
		}
		if (!tstream.lookahead(3).getImage().equals("CDATA"))
		{
			return false;
		}
		if (tstream.lookahead(4).getType() != XmlTokenType.OPEN_BRACKET)
		{
			return false;
		}
		return true;
	}
}
